﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using Cofe.Core.Validater;
using Cofe.Core.Property;
using System.ComponentModel.Composition;
using Cofe.Core.Interfaces;

namespace Cofe.Core.Filter
{
    public class PropertyEntryFilter : EntryFilterBase, IPropertyEntryFilter
    {
        #region Factory

        [Export(typeof(ICofeService))]
        [ServicePriority(ServicePriorityAttribute.DefaultPriority_NONE)]
        public class Factory : IFilterFactory
        {
            #region Constructor

            #endregion

            #region Methods

            private Dictionary<string, Type> getSupportTypes()
            {
                var retVal = new Dictionary<string, Type>();
                foreach (var p in PropertyDictionary.Properties)
                {
                    string alias = DecoratorExtension.getAlias(p);
                    if (!(string.IsNullOrEmpty(alias)))
                        retVal.Add(alias.ToLower(), typeof(PropertyEntryFilter));
                }

                return retVal;
            }

            public T Construct<T>(string name, string value)
                where T : IFilter
            {
                if (typeof(T) == typeof(IEntryFilter))
                {
                    if (SupportedFilterTypes.Keys.Contains(name))
                    {
                        object property = PropertyDictionary.GetProperty(name);
                        return (T)(object)new PropertyEntryFilter(property, value);
                    }
                }

                throw new NotSupportedException();
            }

            #endregion

            #region Data

            private IPathParser[] _pathParsers = null;
            private IPropertyDictionary _propertyDictionary = null;
            Dictionary<string, Type> _cacheDic = null;

            #endregion

            #region Public Properties

            public Dictionary<string, Type> SupportedFilterTypes
            {
                get { if (_cacheDic == null) _cacheDic = getSupportTypes(); return _cacheDic; }
            }

            public IPathParser[] PathParsers
            {
                get { return _pathParsers ?? CofeServices.ServiceLocater.FindAllServices<IPathParser>().ToArray(); }
                set { _pathParsers = value; }
            }
            public IPropertyDictionary PropertyDictionary
            {
                get { return _propertyDictionary ?? CofeServices.ServiceLocater.FindService<IPropertyDictionary>(); }
                set { _propertyDictionary = value; }
            }

            #endregion
        }

        #endregion

        #region Constructor

        public PropertyEntryFilter(object property, string value, string id = "")
            : base(value, id)
        {
            SupportedMatchType = MatchType.MatchThisEntry;
            Property = property;
        }

        #endregion

        #region Methods

        public override string Type
        {
            get
            {
                return
                    DecoratorExtension.getAlias(Property).ToLower();
            }
        }

        public override MatchType matches(
            IPropertyHost entry,
            params IOptionFilter[] options)
        {
            bool match = false;

            if (entry.Behaviors.IsPropertySupported(Property))
            {
                int op = Value.StartsWith(">") ? 1 :
                    Value.StartsWith("<") ? -1 : 0;
                string value = Value.TrimStart('<', '>');
                var entryValue = entry.Behaviors.GetProperty(Property);

                Func<int, int, bool> sameMagnitude =
                    (a, b) => (a < 0 && b < 0) || (a > 0 && b > 0);

                if (op == 0)
                {
                    match = entryValue.Value.ToString().IndexOf(value,
                        StringComparison.OrdinalIgnoreCase) != -1;
                }
                else
                {
                    try
                    {
                        switch (PropertyTypeExtension
                            .GetDefaultPropertyType(Property).ToString())
                        {
                            case "System.Int16":
                            case "System.Int32":
                            case "System.Int64":
                                match = sameMagnitude(op,
                                    entryValue.ValueAsInt64.CompareTo(
                                    Int64.Parse(value)));
                                break;
                            case "System.DateTime":
                                match = sameMagnitude(op,
                                    entryValue.ValueAsLocalDateTime.CompareTo(
                                    DateTime.Parse(value)));
                                break;
                        }
                    }
                    catch (Exception)
                    {
                        //Console.WriteLine("PropertyFilter " + ex.Message);
                    }
                }
            }

            return match ? MatchType.MatchThisEntry : MatchType.None;
        }

        #endregion

        #region Data

        #endregion

        #region Public Properties

        public object Property { get; protected set; }

        #endregion

    }
}
